約 3,610,105 件
https://w.atwiki.jp/zukunashi-yarou/pages/37.html
複数のボールと衝突 複数のオブジェクトと衝突処理を試す。 x, y, z方向に10x10x10の球体を配置して衝突実験。 #include ode/ode.h #include drawstuff/drawstuff.h #include vector #ifdef dDOUBLE #define dsDrawSphere dsDrawSphereD #define dsDrawBox dsDrawBoxD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawLine dsDrawLineD #endif class Shape { public virtual void draw() = 0; }; class Sphere public Shape { protected dBodyID m_body; dGeomID m_geom; public Sphere(dWorldID world, dSpaceID space, dReal x, dReal y, dReal z) { dReal radius = 0.5; // 生成 m_body = dBodyCreate( world ); m_geom = dCreateSphere(space, radius); dGeomSetBody(m_geom, m_body); // 位置設定 dBodySetPosition(m_body, x, y, z); // 質量設定 dMass m; dMassSetZero( m); dMassSetSphereTotal( m, 1.0, radius); dBodySetMass(m_body, m); } ~Sphere() { dBodyDestroy(m_body); dGeomDestroy(m_geom); } virtual void draw() { //dsSetTexture (DS_CHECKERED); dsSetTexture (DS_WOOD); //dsSetColor( 1.0f, 1.0f, 0.0f ); // RGB Color dsSetColorAlpha(0.75, 0.3, 0.3, 1.0); dsDrawSphere( dGeomGetPosition( m_geom ), dGeomGetRotation( m_geom ), dGeomSphereGetRadius(m_geom) ); } }; static std vector Shape* shapeList; static dWorldID world; static dSpaceID space; static dJointGroupID contact_group; // 衝突検出用関数 static void nearCallback( void *data, dGeomID o1, dGeomID o2 ) { static const int MAX_CONTACTS = 4; dBodyID b1 = dGeomGetBody( o1 ); dBodyID b2 = dGeomGetBody( o2 ); if ( b1 b2 dAreConnectedExcluding( b1, b2, dJointTypeContact ) ) return; dContact contact[MAX_CONTACTS]; int numc = dCollide( o1, o2, MAX_CONTACTS, contact[0].geom, sizeof( dContact ) ); if (numc 0) { for (int i=0; i numc; i++) { // 物体同士の接触時のパラメータ設定 contact[i].surface.mode = dContactBounce | dContactSoftCFM; contact[i].surface.mu = dInfinity; // 摩擦係数 contact[i].surface.bounce = 0.5; // 反発係数 contact[i].surface.bounce_vel = 0.01; contact[i].surface.soft_cfm = 0.0001; // CFM設定 // 衝突の発生 dJointID c = dJointCreateContact( world, contact_group, contact+i ); dJointAttach( c, b1, b2 ); } } } // start simulation - set viewpoint static void start() { static float xyz[3] = { 0.f, 20.f, 10.f }; static float hpr[3] = {-90.f, -20.f, 0.f }; dsSetViewpoint( xyz, hpr ); // カメラ位置と方向設定 } // simulation loop static void simLoop( int pause ) { // Ctl+p が押されたらifに入らない if (!pause) { dSpaceCollide( space, 0, nearCallback ); // 衝突検出 //dWorldStep( world, 0.01 ); dWorldQuickStep( world, 0.01 ); dJointGroupEmpty( contact_group ); } // Shapeの表示 std vector Shape* iterator it = shapeList.begin(); while (it != shapeList.end()) { (*it)- draw(); ++it; } } int main( int argc, char* argv[] ) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = start; fn.step = simLoop; fn.command = 0; fn.stop = 0; fn.path_to_textures = "../../../textures"; // ODE初期化 dInitODE2(0); dAllocateODEDataForThread(dAllocateMaskAll); // World,Space生成 world = dWorldCreate(); dWorldSetGravity(world, 0.0, 0.0, -9.8); dWorldSetCFM (world,1e-5); dWorldSetLinearDamping(world, 0.00001); dWorldSetAngularDamping(world, 0.005); dWorldSetMaxAngularSpeed(world, 200); dWorldSetERP(world, 0.2); dWorldSetContactSurfaceLayer (world,0.001); //space = dSimpleSpaceCreate (0); space = dHashSpaceCreate (0); contact_group = dJointGroupCreate(0); // 地面生成 dCreatePlane(space, 0, 0, 1, 0); // シェイプ生成 for (int z=0; z 10; z++) { for (int y=0; y 10; y++) { for (int x=0; x 10; x++) { dReal px = (dReal)x*1.1-5.0 + (dReal)(rand()%100)/100000.0; dReal py = (dReal)y*1.1-5.0 + (dReal)(rand()%100)/100000.0; dReal pz = (dReal)z*1.1+1.0 ; shapeList.push_back(new Sphere(world, space, px, py, pz)); } } } dsSimulationLoop(argc, argv, 320, 240, fn); dJointGroupDestroy(contact_group); dWorldDestroy(world); dSpaceDestroy(space); return 0; }
https://w.atwiki.jp/bambooflow/pages/230.html
glutでODE テスト中 ode_draw08.zip ObjectBase.h ObjectBase.cpp SimpleSphere.h SimpleSphere.cpp SimpleBox.h SimpleBox.cpp SimpleCylinder.h SimpleCylinder.cpp SimpleCappedCylinder.h SimpleCappedCylinder.cpp SampleMonkey.h SampleMonkey.cpp XReader.h StlReader.h main.cpp 剛体表示。落下。 地面に衝突。 実装機能Sphere(球体)の生成、表示 glutによるグラフィック表示 Box(箱)の生成、表示 vectorにより、3D表示の自動化 groundをObjectBaseに変更 Cylinder(円柱)、CappedCylinder(カプセル)オブジェクト追加 影表示(簡易のシャドウマトリックスを使用) gluiによるGUI表示。 カメラ操作をgluiに変更。(まだ適当。) STLファイル、Xファイル読み込み、表示(Meshのみ) ハイトフィールド表示(bitmapデータから) 下記のチュートリアルを参考にしてます。 http //artis.imag.fr/Membres/Xavier.Decoret/resources/ode/tutorial1.html ObjectBase.h 重要な部分は、render()とrenderInLocalFrame()=0の実装。 3D表示のための簡易的な機構になります。 #include ode/ode.h class ObjectBase { protected dBodyID m_body; dGeomID m_geom; bool m_flagShadow; public ObjectBase(); ~ObjectBase(); virtual void render(); virtual void renderShadow(); void setPosition(dReal x, dReal y, dReal z); const dReal* getPosition() const; const dBodyID body() const; const dGeomID geom() const; protected virtual void renderInLocalFrame() const = 0; }; void ObjectBase render() const { const dReal *p = dBodyGetPosition(body); const dReal *r = dBodyGetRotation(body); float m[16]; m[ 0] = (GLfloat)r[ 0]; m[ 1] = (GLfloat)r[ 4]; m[ 2] = (GLfloat)r[ 8]; m[ 3] = (GLfloat)0; m[ 4] = (GLfloat)r[ 1]; m[ 5] = (GLfloat)r[ 5]; m[ 6] = (GLfloat)r[ 9]; m[ 7] = (GLfloat)0; m[ 8] = (GLfloat)r[ 2]; m[ 9] = (GLfloat)r[ 6]; m[10] = (GLfloat)r[10]; m[11] = (GLfloat)0; m[12] = (GLfloat)p[ 0]; m[13] = (GLfloat)p[ 1]; m[14] = (GLfloat)p[ 2]; m[15] = (GLfloat)1; glMultMatrixf( m ); renderInLocalFrame(); }
https://w.atwiki.jp/bambooflow/pages/100.html
10. 衝突検出210.7. Geometry Classes10.7.1. Sphere Class 10.7.2. Box Class 10.7.3. Plane Class 10.7.4. Capped Cylinder Class 10.7.5. Ray Class 10.7.6. Triangle Mesh Class 10.7.7. Geometry Transform Class 10.8. User defined classes 10. 衝突検出2 10.7. Geometry Classes 10.7.1. Sphere Class dGeomID dCreateSphere (dSpaceID space, dReal radius); Create a sphere geom of the given radius, and return its ID. If space is nonzero, insert it into that space. The point of reference for a sphere is its center. 与えられたradiusの球体geomを生成し、そのIDを返す。 spaceがゼロでない場合、スペースに挿入する。参照ポイントはその球体の中心である。 void dGeomSphereSetRadius (dGeomID sphere, dReal radius); Set the radius of the given sphere. 与えられた球体の半径を設定する。 dReal dGeomSphereGetRadius (dGeomID sphere); Return the radius of the given sphere. 与えられた球体の半径を返す。 dReal dGeomSpherePointDepth (dGeomID sphere, dReal x, dReal y, dReal z); Return the depth of the point (x,y,z) in the given sphere. Points inside the geom will have positive depth, points outside it will have negative depth, and points on the surface will have zero depth. 10.7.2. Box Class dGeomID dCreateBox (dSpaceID space, dReal lx, dReal ly, dReal lz); Create a box geom of the given x/y/z side lengths (lx,ly,lz), and return its ID. If space is nonzero, insert it into that space. The point of reference for a box is its center. 与えられたx/y/zの側面の長さ( lx, ly, lz )のgeomボックスを生成し、そのIDを返す。splaceがゼロでない場合、スペースに挿入する。参照ポイントはそのボックスの中心である。 void dGeomBoxSetLengths (dGeomID box, dReal lx, dReal ly, dReal lz); Set the side lengths of the given box. 与えられたboxの側面を設定する。 void dGeomBoxGetLengths (dGeomID box, dVector3 result); Return in result the side lengths of the given box. 与えられたboxの側面をresultとして返す。 dReal dGeomBoxPointDepth (dGeomID box, dReal x, dReal y, dReal z); Return the depth of the point (x,y,z) in the given box. Points inside the geom will have positive depth, points outside it will have negative depth, and points on the surface will have zero depth. 10.7.3. Plane Class dGeomID dCreatePlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d); Create a plane geom of the given parameters, and return its ID. If space is nonzero, insert it into that space. The plane equation is a*x+b*y+c*z = d The plane s normal vector is (a,b,c), and it must have length 1. Planes are non-placeable geoms. This means that, unlike placeable geoms, planes do not have an assigned position and rotation. This means that the parameters (a,b,c,d) are always in global coordinates. In other words it is assumed that the plane is always part of the static environment and not tied to any movable object. void dGeomPlaneSetParams (dGeomID plane, dReal a, dReal b, dReal c, dReal d); Set the parameters of the given plane. 与えられたplaneのパラメータを設定する。 void dGeomPlaneGetParams (dGeomID plane, dVector4 result); Return in result the parameters of the given plane. 与えられたplaneのパラメータをresultとして返す。 dReal dGeomPlanePointDepth (dGeomID plane, dReal x, dReal y, dReal z); Return the depth of the point (x,y,z) in the given plane. Points inside the geom will have positive depth, points outside it will have negative depth, and points on the surface will have zero depth. 10.7.4. Capped Cylinder Class dGeomID dCreateCCylinder (dSpaceID space, dReal radius, dReal length); Create a capped cylinder geom of the given parameters, and return its ID. If space is nonzero, insert it into that space. A capped cylinder is like a normal cylinder except it has half-sphere caps at its ends. This feature makes the internal collision detection code particularly fast and accurate. The cylinder s length, not counting the caps, is given by length. The cylinder is aligned along the geom s local Z axis. The radius of the caps, and of the cylinder itself, is given by radius. void dGeomCCylinderSetParams (dGeomID ccylinder, dReal radius, dReal length); Set the parameters of the given capped cylinder. void dGeomCCylinderGetParams (dGeomID ccylinder, dReal *radius, dReal *length); Return in radius and length the parameters of the given capped cylinder. dReal dGeomCCylinderPointDepth (dGeomID ccylinder, dReal x, dReal y, dReal z); Return the depth of the point (x,y,z) in the given capped cylinder. Points inside the geom will have positive depth, points outside it will have negative depth, and points on the surface will have zero depth. 10.7.5. Ray Class A ray is different from all the other geom classes in that it does not represent a solid object. It is an infinitely thin line that starts from the geom s position and extends in the direction of the geom s local Z-axis. rayは固体を表さないので他のすべてのgeomクラスとは異なる。 geomの位置からスタートし、geomのローカルのZ軸の方向に伸びる無限に薄いラインである。 Calling dCollide between a ray and another geom will result in at most one contact point. Rays have their own conventions for the contact information in the dContactGeom structure (thus it is not useful to create contact joints from this information) 線と別のgeomの間のdCollideを呼ぶことは、大部分で1つの 接触ポイントで終わる。線はdContactGeom構造体に接触情報の条約を持つ(したがって、この情報から接触ジョイントを生成のために用いられな い): pos - This is the point at which the ray intersects the surface of the other geom, regardless of whether the ray starts from inside or outside the geom. normal - This is the surface normal of the other geom at the contact point. if dCollide is passed the ray as its first geom then the normal will be oriented correctly for ray reflection from that surface (otherwise it will have the opposite sign). depth - This is the distance from the start of the ray to the contact point. Rays are useful for things like visibility testing, determining the path of projectiles or light rays, and for object placement. dGeomID dCreateRay (dSpaceID space, dReal length); Create a ray geom of the given length, and return its ID. If space is nonzero, insert it into that space. void dGeomRaySetLength (dGeomID ray, dReal length); Set the length of the given ray. 与えられたrayの長さを設定する。 dReal dGeomRayGetLength (dGeomID ray); Get the length of the given ray. 与えられたrayの長さを取得する。 void dGeomRaySet (dGeomID ray, dReal px, dReal py, dReal pz, dReal dx, dReal dy, dReal dz); Set the starting position (px,py,pz) and direction (dx,dy,dz) of the given ray. The ray s rotation matrix will be adjusted so that the local Z-axis is aligned with the direction. Note that this does not adjust the ray s length. void dGeomRayGet (dGeomID ray, dVector3 start, dVector3 dir); Get the starting position (start) and direction (dir) of the ray. The returned direction will be a unit length vector. 10.7.6. Triangle Mesh Class A triangle mesh (TriMesh) represents an arbitrary collection of triangles. The triangle mesh collision system has the following features 三角形メッシュ(TriMesh)は、三角形の任意のコレクションを表 す。三角形メッシュ衝突システムは次の特徴を持つ: Any triangle ``soup can be represented --- i.e. the triangles are not required to have any particular strip, fan or grid structure. どんな三角形"スープ"は表すことができる---つまり、三角 形はどんな特殊な一片(ファンか格子構造)も持つことは要求されない。 Triangle meshes can interact with spheres, boxes, rays and other triangle meshes. 三角形メッシュは球体、箱、線、他の三角形メッシュなどと作用 することができる。 It works well for relatively large triangles. 比較的大きな三角形にうまく働く。 It uses temporal coherence to speed up collision tests. When a geom has its collision checked with a trimesh once, data is stored inside the trimesh. This data can be cleared with the dGeomTriMeshClearTCCache function. In the future it will be possible to disable this functionality. それは、衝突試験をスピードを上げるために一時的に結合する。 geomが一度trimeshとの衝突を確認した場合、データはtrimeshの内部で格納される。このデータは dGeomTriMeshClearTCCache関数で取り除くことができる。今後、この機能性を無効にすることは可能である。 Trimesh/Trimesh collisions, perform quite well, but there are three minor caveats The stepsize you use will, in general, have to be reduced for accurate collision resolution. Non-convex shape collision is much more dependent on the collision geometry than primitive collisions. Further, the local contact geometry will change more rapidly (and in a more complex fashion) for non-convex polytopes than it does for simple, convex polytopes such as spheres and cubes. In order to efficiently resolve collisions, dCollideTTL needs the positions of the colliding trimeshes in the previous timestep. This is used to calculate an estimated velocity of each colliding triangle, which is used to find the direction of impact, contact normals, etc. This requires the user to update these variables at every timestep. This update is performed outside of ODE, so it is not included in ODE itself. The code to do this looks something like this const double *DoubleArrayPtr = Bodies[BodyIndex].TransformationMatrix- GetArray(); dGeomTriMeshDataSet( TriMeshData, TRIMESH_LAST_TRANSFORMATION, (void *) DoubleArrayPtr ); The transformation matrix is the standard 4x4 homogeneous transform matrix, and the "DoubleArray" is the standard flattened array of the 16 matrix values. NOTE The triangle mesh class is not final, so in the future API changes might be expected. dTriMeshDataID dGeomTriMeshDataCreate(); void dGeomTriMeshDataDestroy (dTriMeshDataID g); Creates and destroys a dTriMeshData object which is used to store mesh data. void dGeomTriMeshDataBuild (dTriMeshDataID g, const void* Vertices, int VertexStride, int VertexCount, const void* Indices, int IndexCount, int TriStride, const void* Normals); Used for filling a dTriMeshData object with data. No data is copied here, so the pointers passed into this function must remain valid. This is how the strided data works struct StridedVertex { dVector3 Vertex; // 4th component can be left out, reducing memory usage // Userdata }; int VertexStride = sizeof (StridedVertex); struct StridedTri { int Indices[3]; // Userdata }; int TriStride = sizeof (StridedTri); The Normals argument is optional the normals of the faces of each trimesh object. For example, dTriMeshDataID TriMeshData; TriMeshData = dGeomTriMeshGetTriMeshDataID ( Bodies[BodyIndex].GeomID); // as long as dReal == floats dGeomTriMeshDataBuildSingle (TriMeshData, // Vertices Bodies[BodyIndex].VertexPositions, 3*sizeof(dReal), (int) numVertices, // Faces Bodies[BodyIndex].TriangleIndices, (int) NumTriangles, 3*sizeof(unsigned int), // Normals Bodies[BodyIndex].FaceNormals); This pre-calculation saves some time during evaluation of the contacts, but isn t necessary. If you don t want to calculate the face normals before construction (or if you have enormous trimeshes and know that only very few faces will be touching and want to save time), just pass a "NULL" for the Normals argument, and dCollideTTL will take care of the normal calculations itself. void dGeomTriMeshDataBuildSimple (dTriMeshDataID g, const dVector3*Vertices, int VertexCount, const int* Indices, int IndexCount); Simple build function provided for convenience. typedef int dTriCallback (dGeomID TriMesh, dGeomID RefObject, int TriangleIndex); void dGeomTriMeshSetCallback (dGeomID g, dTriCallback *Callback); dTriCallback* dGeomTriMeshGetCallback (dGeomID g); Optional per triangle callback. Allows the user to say if collision with a particular triangle is wanted. If the return value is zero no contact will be generated. typedef void dTriArrayCallback (dGeomID TriMesh, dGeomID RefObject, const int* TriIndices, int TriCount); void dGeomTriMeshSetArrayCallback (dGeomID g, dTriArrayCallback* ArrayCallback); dTriArrayCallback *dGeomTriMeshGetArrayCallback (dGeomID g); Optional per geom callback. Allows the user to get the list of all intersecting triangles in one shot. typedef int dTriRayCallback (dGeomID TriMesh, dGeomID Ray, int TriangleIndex, dReal u, dReal v); void dGeomTriMeshSetRayCallback (dGeomID g, dTriRayCallback* Callback); dTriRayCallback *dGeomTriMeshGetRayCallback (dGeomID g); Optional Ray callback. Allows the user to determine if a ray collides with a triangle based on the barycentric coordinates of an intersection. The user can for example sample a bitmap to determine if a collision should occur. dGeomID dCreateTriMesh (dSpaceID space, dTriMeshDataID Data, dTriCallback *Callback, dTriArrayCallback * ArrayCallback, dTriRayCallback* RayCallback); Constructor. The Data member defines the vertex data the newly created triangle mesh will use. void dGeomTriMeshSetData (dGeomID g, dTriMeshDataID Data); Replaces the current data. void dGeomTriMeshClearTCCache (dGeomID g); Clears the internal temporal coherence caches. void dGeomTriMeshGetTriangle (dGeomID g, int Index, dVector3 *v0, dVector3 *v1, dVector3 *v2); Retrieves a triangle in object space. The v0, v1 and v2 arguments are optional. void dGeomTriMeshGetPoint (dGeomID g, int Index, dReal u, dReal v, dVector3 Out); Retrieves a position in object space based on the incoming data. void dGeomTriMeshEnableTC(dGeomID g, int geomClass, int enable); int dGeomTriMeshIsTCEnabled(dGeomID g, int geomClass); These functions can be used to enable/disable the use of temporal coherence during tri-mesh collision checks. Temporal coherence can be enabled/disabled per tri-mesh instance/geom class pair, currently it works for spheres and boxes. The default for spheres and boxes is false . The enable param should be 1 for true, 0 for false. Temporal coherence is optional because allowing it can cause subtle efficiency problems in situations where a tri-mesh may collide with many different geoms during its lifespan. If you enable temporal coherence on a tri-mesh then these problems can be eased by intermittently calling dGeomTriMeshClearTCCache for it. 10.7.7. Geometry Transform Class A geometry transform `T is a geom that encapsulates another geom `E , allowing E to be positioned and rotated arbitrarily with respect to its point of reference. 形状変形’T’は別のgeom’E’をカプセルに入れるgeomで、E が参照ポイントに関して任意に位置し回転することを可能にする。 Most placeable geoms (like the sphere and box) have their point of reference corresponding to their center of mass, allowing them to be easily connected to dynamics objects. Transform objects give you more flexibility - for example, you can offset the center of a sphere, or rotate a cylinder so that its axis is something other than the default. もっとも配置できるgeom(球体やボックスのような)は、それらの質 量中心に対応する参照ポイントを持ち、力学オブジェクトに容易に接続が可能である。変形オブジェクトは弾力性が与えられる。例えば、球体の中心を補正でき たり、または軸がデフォルトでないようなシリンダの回転を補正できる。 T mimics the object E that it encapsulates T is inserted into a space and attached to a body as though it was E. E itself must not be inserted into a space or attached to a body. E s position and rotation are set to constant values that say how it is transformed relative to T. If E s position and rotation are left at their default values, T will behave exactly like E would have if you had used it directly. Tはカプセル化されたEオブジェクトに似た構造である:Tはスペースに 挿入され、Eのような剛体に繋がれる。E自体はスペースに挿入または、剛体に繋がれてはいけない。Eの位置と回転は、Tに関係したものを変形させた一定値 に設定される。Eの位置と回転がデフォルト値で残された場合、それを直接使用していたならば、Eが持つように、Tは正確に作用するだろう。 dGeomID dCreateGeomTransform (dSpaceID space); Create a new geometry transform object, and return its ID. If space is nonzero, insert it into that space. On creation the encapsulated geometry is set to 0. 新しい形状変形したオブジェクトを生成し、そのIDを返す。space が非ゼロである場合は、そのspaceに挿入する。生成においては、カプセルに入れられた幾何学は0に設定される。 void dGeomTransformSetGeom (dGeomID g, dGeomID obj); Set the geom that the geometry transform g encapsulates. The object obj must not be inserted into any space, and must not be associated with any body. カプセルに入った形状変形したgのgeomを設定する。objオブジェ クトは任意のスペースに挿入されてはならない、そして任意の剛体に関係していてはいけない。 If g has its clean-up mode turned on, and it already encapsulates an object, the old object will be destroyed before it is replaced with the new one. gがクリーンアップ・モードで付けているとき、それが既にオブジェクト をカプセルに入れる場合、新しいものと取り替えられる前に、古いオブジェクトが破棄される。 dGeomID dGeomTransformGetGeom (dGeomID g); Get the geom that the geometry transform g encapsulates. カプセル化された幾何学トランスフォームのgであるgeomを取得す る。 void dGeomTransformSetCleanup (dGeomID g, int mode); int dGeomTransformGetCleanup (dGeomID g); Set and get the clean-up mode of geometry transform g. If the clean-up mode is 1, then the encapsulated object will be destroyed when the geometry transform is destroyed. If the clean-up mode is 0 this does not happen. The default clean-up mode is 0. 形状変形gのクリーンアップモードの設定取得を行う。クリーンアップ モードが1の場合、カプセル化されたオブジェクトは形状変形が破棄されたとき破棄される。クリーンアップモードが0の場合、なにも起こらない。デフォルト のクリーンアップモードは0である。 void dGeomTransformSetInfo (dGeomID g, int mode); int dGeomTransformGetInfo (dGeomID g); Set and get the "information" mode of geometry transform g. The mode can be 0 or 1. The default mode is 0. With mode 0, when a transform object is collided with another object (using dCollide (tx_geom,other_geom,...)), the g1 field of the dContactGeom structure is set to the geom that is encapsulated by the transform object. This value of g1 allows the caller to interrogate the type of the geom that is transformed, but it does not allow the caller to determine the position in global coordinates or the associated body, as both of these properties are used differently for encapsulated geoms. With mode 1, the g1 field of the dContactGeom structure is set to the transform object itself. This makes the object appear just like any other kind of geom, as dGeomGetBody will return the attached body, and dGeomGetPosition will return the global position. To get the actual type of the encapsulated geom in this case, dGeomTransformGetGeom must be used. 10.8. User defined classes ODE s geometry classes are implemented internally as C++ classes. If you want to define your own geometry classes you can do this in two ways Use the C functions in this section. This has the advantage of providing a clean separation between your code and ODE. Add the classes directly to ODE s source code. This has the advantage that you can use C++ so the implementation will potentially be a bit cleaner. This is also the preferred method if your collision class is generally useful and you want to contribute it to the public source base. What follows is the C API for user defined geometry classes. Every user defined geometry class has a unique integer number. A new geometry class (call it `X ) must provide the following to ODE Functions that will handle collision detection and contact generation between X and one or more other classes. These functions must be of type dColliderFn, which is defined as typedef int dColliderFn (dGeomID o1, dGeomID o2, int flags, dContactGeom *contact, int skip); This has exactly the same interface as dCollide. Each function will handle a specific collision case, where o1 has type X and o2 has some other known type. A "selector" function, of type dGetColliderFnFn, which is defined as typedef dColliderFn * dGetColliderFnFn (int num); This function takes a class number (num), and returns the collider function that can handle colliding X with class num. It should return 0 if X does not know how to collide with class num. Note that if classes X and Y are to collide, only one needs to provide a function to collide with the other. This function is called infrequently - the return values are cached and reused. A function that will compute the axis aligned bounding box (AABB) of instances of this class. This function must be of type dGetAABBFn, which is defined as typedef void dGetAABBFn (dGeomID g, dReal aabb[6]); This function is given g, which has type X, and returns the axis-aligned bounding box for g. The aabb array has elements (minx, maxx,miny,maxy,minz,maxz). If you don t want to compute tight bounds for the AABB, you can just supply a pointer to dInfiniteAABB, which returns +/- infinity in each direction. The number of bytes of "class data" that instances of this class need. For example a sphere stores its radius in the class data area, and a box stores its side lengths there. The following things are optional for a geometry class A function that will destroy the class data. Most classes will not need this function, but some will want to deallocate heap memory or release other resources. This function must be of type dGeomDtorFn, which is defined as typedef void dGeomDtorFn (dGeomID o); The argument o has type X. A function that will test whether a given AABB intersects with an instance of X. This is used as an early-exit test in the space collision functions. This function must be of type dAABBTestFn, which is defined as typedef int dAABBTestFn (dGeomID o1, dGeomID o2, dReal aabb2[6]); The argument o1 has type X. If this function is provided it is called by dSpaceCollide when o1 intersects geom o2, which has an AABB given by aabb2. It returns 1 if aabb2 intersects o1, or 0 if it does not. This is useful, for example, for large terrains. Terrains typically have very large AABBs, which
https://w.atwiki.jp/opengl/pages/319.html
箱が上から落ちてきて、地面でバウンドします。 値を設定するだけで、後は勝手にシミュレーションしてくれます。 ファイル main.cpp main.cpp #pragma comment(linker, /SUBSYSTEM WINDOWS /ENTRY mainCRTStartup ) #pragma comment(lib, ode_doubled.lib ) #include GL/freeglut/freeglut.h #include ode/ode.h #include vector using namespace std; #define WIDTH 320 #define HEIGHT 240 #define ODE_MAX_CONTACTS 1024 //ライトの位置 GLfloat lightpos[] = { 2.0, 4.0, 1.0, 0.0 }; const GLfloat FOV = 45.0f; //ODE関連変数 bool WorldCreated = false; //ODEワールド作成フラグ double g_fDt = 0.005; //タイムステップ幅 dWorldID World; //ODEワールド dSpaceID Space; //ODE空間 dJointGroupID JointGroupID;//ジョイントグループ dGeomID Ground; //床 vector dBodyID ODE_obj; //オブジェクト(立方体) dBodyID CubeID = 0; //立方体のID double CubeSize = 0.1; //立方体の大きさ bool CrtContact = false; //3つのベクトル struct Vector3f{ float x; float y; float z; Vector3f(){}; Vector3f(float _x,float _y,float _z){ x=_x;y=_y;z=_z; }; }vec3d; Vector3f operator-(Vector3f a,Vector3f b){ a.x-=b.x; a.y-=b.y; a.z-=b.z; return a; } inline Vector3f ODE_GetPos(dBodyID body) { Vector3f pos; pos.x = (float)dBodyGetPosition(body)[0]; pos.y = (float)dBodyGetPosition(body)[1]; pos.z = (float)dBodyGetPosition(body)[2]; return pos; } inline Vector3f ODE_GetPosG(dGeomID geom) { Vector3f pos; pos.x = (float)dGeomGetPosition(geom)[0]; pos.y = (float)dGeomGetPosition(geom)[1]; pos.z = (float)dGeomGetPosition(geom)[2]; return pos; } inline void ODE_GetRotMat(dBodyID body, GLfloat m[16]) { m[0] = (GLfloat)dBodyGetRotation(body)[0]; m[1] = (GLfloat)dBodyGetRotation(body)[4]; m[2] = (GLfloat)dBodyGetRotation(body)[8]; m[3] = 0.0f; m[4] = (GLfloat)dBodyGetRotation(body)[1]; m[5] = (GLfloat)dBodyGetRotation(body)[5]; m[6] = (GLfloat)dBodyGetRotation(body)[9]; m[7] = 0.0f; m[8] = (GLfloat)dBodyGetRotation(body)[2]; m[9] = (GLfloat)dBodyGetRotation(body)[6]; m[10] = (GLfloat)dBodyGetRotation(body)[10]; m[11] = 0.0f; m[12] = (GLfloat)dBodyGetRotation(body)[3]; m[13] = (GLfloat)dBodyGetRotation(body)[7]; m[14] = (GLfloat)dBodyGetRotation(body)[11]; m[15] = 1.0f; } inline double dot(const Vector3f a, const Vector3f b) { return a.x*b.x + a.y*b.y + a.z*b.z; } inline double norm(const Vector3f a) { return sqrt(dot(a,a)); } //衝突コールバック関数用のデータ struct NearCallData { dWorldID* world; dJointGroupID* contact; }; //ODEの衝突処理 2つの物体の距離が近いときにODEから呼ばれるコールバック関数 static void ODENearCallback(void *data, dGeomID o1, dGeomID o2){ // 衝突判定する物体のボディIDを取得 dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if(b1 b2 dAreConnected(b1, b2)){ return; } // 接触判定 dContact contact[ODE_MAX_CONTACTS]; int n = dCollide(o1, o2, ODE_MAX_CONTACTS, contact[0].geom, sizeof(dContact)); if(n 0){ // 1点以上での接触があった場合 for(int i = 0; i n; ++i){ // 接触ごとにパラメータを設定 contact[i].surface.mode = dContactBounce; contact[i].surface.bounce = 0.5; // 弾力性 contact[i].surface.bounce_vel = 0.001; dJointID c = dJointCreateContact(*(((NearCallData*)data)- world), *(((NearCallData*)data)- contact), contact+i); dJointAttach(c, dGeomGetBody(o1), dGeomGetBody(o2)); } } } //ODEの計算ステップを進める void StepODE(void){ NearCallData data; data.world = World; data.contact = JointGroupID; dSpaceCollide(Space, data, ODENearCallback); dWorldQuickStep(World, g_fDt); dJointGroupEmpty(JointGroupID); // 立方体を回転(角速度を設定) if(CubeID){ dBodySetAngularVel(CubeID, 0.0, 10.0, 10.0); } } //ODE空間に立方体を配置 void SetODECube(Vector3f pos, double len){ double d = 10*len; if(!ODE_obj.empty()){ // 最後に追加したオブジェクトとの距離 d = norm(pos-ODE_GetPos(ODE_obj.back())); } // 追加位置に別のオブジェクトがなければ追加 if(d len){ // 立方体の重さを算出 dMass mass; dMassSetBox( mass, 1.0, (dReal)len, (dReal)len, (dReal)len); dMassAdjust( mass, 1.0); // 形状の作成 dGeomID geom = dCreateBox(Space, (dReal)len, (dReal)len, (dReal)len); // ボディの作成 dBodyID body = dBodyCreate(World); dBodySetMass(body, mass); dGeomSetBody(geom, body); // 位置を設定 dBodySetPosition(body, pos.x, pos.y, pos.z); ODE_obj.push_back(body); } } void InitODE(void){ dInitODE2(0); //ODE空間の破棄(既に存在していれば) if(WorldCreated){ dJointGroupDestroy(JointGroupID); dSpaceDestroy(Space); dWorldDestroy(World); } //ODE空間の生成 World = dWorldCreate(); Space = dHashSpaceCreate(0); JointGroupID = dJointGroupCreate(0); //ODE空間パラメータの設定 dWorldSetGravity(World, 0, -9.8, 0); //重力 dWorldSetCFM(World, 1e-5); //グローバルCFM(constraint force mixing) Typical Value [10^-9, 1.0] dWorldSetContactMaxCorrectingVel(World, 0.1); dWorldSetERP(World, 0.8); //グローバルERP dWorldSetLinearDamping(World, 0.00001); //空気抵抗(平行移動速度) dWorldSetAngularDamping(World, 0.005); //空気抵抗(角速度) dWorldSetMaxAngularSpeed(World, 200); //最大角速度 dWorldSetContactSurfaceLayer(World, 0.05); //接触層の厚さ(この層内にいる物体は接触しているとする) dWorldSetAutoDisableFlag(World, 1); //しばらく動いていないbodyを自動でdisableする WorldCreated = true; // 床 Ground = dCreatePlane(Space, 0, 1, 0, 0); // 立方体 CrtContact = false; SetODECube(Vector3f(0.0f, 0.8f, 0.0f), CubeSize); } void CleanODE(void){ if(WorldCreated){ for(int i = 0; i (int)ODE_obj.size(); ++i){ dBodyDestroy(ODE_obj[i]); } dGeomDestroy(Ground); dJointGroupDestroy(JointGroupID); dSpaceDestroy(Space); dWorldDestroy(World); dCloseODE(); } } //シーンの描画 void DrawScene(void){ GLfloat blue[] = { 0.4f, 0.4f, 1.0f, 1.0f };//青 static const GLfloat spec[] = { 0.3f, 0.3f, 0.3f, 1.0f }; //鏡面反射色 static const GLfloat ambi[] = { 0.1f, 0.1f, 0.1f, 1.0f }; //環境光 glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glCullFace(GL_BACK); glEnable(GL_CULL_FACE); glDisable(GL_COLOR_MATERIAL); // 材質を設定 glMaterialfv(GL_FRONT, GL_SPECULAR, spec); glMaterialfv(GL_FRONT, GL_AMBIENT, ambi); glMaterialf(GL_FRONT, GL_SHININESS, 50.0); glPolygonMode(GL_FRONT, GL_FILL); glColor3f(0.0, 0.0, 1.0); // 立方体を描画 for(int i = 0; i (int)ODE_obj.size(); ++i){ dBodyID body = ODE_obj[i]; glMaterialfv(GL_FRONT, GL_DIFFUSE, blue); glPushMatrix(); Vector3f pos; GLfloat m[16]; pos = ODE_GetPos(body); ODE_GetRotMat(body, m); glTranslatef(pos.x, pos.y, pos.z); glMultMatrixf(m); // 形状の取得 dGeomID geom = dBodyGetFirstGeom(body); // 形状タイプの取得 int type = dGeomGetClass(geom); // 形状ごとの描画 if(type == dBoxClass){ dReal sl[4]; dGeomBoxGetLengths(geom, sl); glScalef((float)sl[0], (float)sl[1], (float)sl[2]); glutSolidCube(1.0); } else if(type == dSphereClass){ dReal rad = dGeomSphereGetRadius(geom); glutSolidSphere(rad, 32, 16); } glPopMatrix(); } // 床を描画 GLfloat color[] = { 0.8f, 0.8f, 0.8f, 1.0f }; glMaterialfv(GL_FRONT, GL_DIFFUSE, color); glPushMatrix(); glNormal3f(0.0, 1.0, 0.0); glBegin(GL_POLYGON); glVertex3f(-10.0, 0.0, -10.0); glVertex3f(-10.0, 0.0, 10.0); glVertex3f( 10.0, 0.0, 10.0); glVertex3f( 10.0, 0.0, -10.0); glEnd(); glPopMatrix(); } void display(void){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, WIDTH, HEIGHT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(FOV, (float)WIDTH/(float)HEIGHT, 0.01f, 20.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPushMatrix(); //視点の設定 gluLookAt(1.0,0.5,1.0, //カメラの座標 0.0,0.0,0.0, // 注視点の座標 0.0,1.0,0.0); // 画面の上方向を指すベクトル // 光源位置 glLightfv(GL_LIGHT0, GL_POSITION, lightpos); DrawScene(); glPopMatrix(); glutSwapBuffers(); } void idle(void){ StepODE(); glutPostRedisplay(); Sleep(1); } void Init(void){ // 背景色 glClearColor(1.0, 1.0, 1.0, 1.0); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_NORMALIZE); InitODE(); } int main(int argc, char *argv[]) { glutInitWindowPosition(100, 100); glutInitWindowSize(WIDTH, HEIGHT); glutInit( argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutCreateWindow( Hello ODE World!! ); glutDisplayFunc(display); glutIdleFunc(idle); Init(); glutMainLoop(); CleanODE(); return 0; }
https://w.atwiki.jp/vsync/pages/3.html
■Open Dynamics Engine について 念のためこのサイトは個人の覚書なのでたいした参考にはなりません。 ODE(Open Dynamics Engine、オープン・ダイナミクス・エンジン)とは、オープンソース方式で開発されている物理演算エンジンである。BSDライセンスとLGPLの両ライセンスが適用されている。 機能はイマイチな気もするが、自分で手を加えるならこれくらいでよさそう。 ■描画機能 簡易描画ライブラリとしてOpenGLをベースに作られたdrawstuffが付属してる。これは実行結果を簡易的に描画するのが目的でありODE自体の一部ではない。 これは動作とコリジョン確認程度、表現力には期待しないのでこれでおk ■採用実績 ここらへんで使われてるらしい↓ ブラッドレイン2 S.T.A.L.K.E.R グーの惑星 ■インストール(Windows) ここら辺からDL http //sourceforge.net/projects/opende/files/ 深い意味は無いが解説ページのバージョンに合わせて以下のをインストール ode-src-0.9.zip インストールはzipを展開して如何のディレクトリ掘ってコピーするだけ。 C \ode-0.9 Cルートにある方が都合が良いらしい。 ■ビルド&実行 以下にvcプロジェクトがあるから適当にコンパイル実行、自分の場合VisualStudio2008EEで問題無く ビルド実行。 C \ode-0.9\build\vs2005 ■参考に成りそうなサイト 基本からならここかな↓ http //demura.net/category/9ode 『Open Dynamics Engine(ODE)』の独自マニュアル http //www.koj-m.sakura.ne.jp/ode/ こちらの↓サイトが非常に整理されていて参考になる http //www.crystal-creation.com/robot/technical-information/physics-engine/ode/ ODE 0.5ドキュメント日本語訳 http //f42.aaa.livedoor.jp/~hassaku/crswikicrs/?ODE%CC%F5 モバイルから見れる↓ http //www10.atwiki.jp/bambooflow/m/pages/212.html?guid=on
https://w.atwiki.jp/bambooflow/pages/171.html
転がり摩擦 転がり摩擦計算 全ソースコード ODEは、静止摩擦はあるようですが、転がり摩擦はないみたいです。 なので、平面でボールを転がすとどこまでも転がっていってしまいます。 そこで、転がり摩擦を簡易的に作ってみました。 計算が正しいかどうかは知りません。 (計算は苦手なので。) もっと素晴らしい方法があるかもしれません。 計算 どこかのページで、転がり摩擦は次の式であると書いてあったので、これを使ってみます。 F = f * (W / r) F 転がり摩擦[N] f 転がり摩擦係数[mm] r 物体の半径[mm] 今回は、球体のみ考えます。円柱とかはとりあえず置いておきます。 ODEで転がり摩擦をあたえるには、dBodyAddForceもしくはdBodyAddTorqueがよさそうに思います。 ここではAddTorqueを使ってみました。 rolling_function関数で、剛体に転がり摩擦をAddTorqueにて与えています。 タイミングは、ボールが物体と衝突しているときのみでよいので、nearCallback関数内で呼ぶようにしています。 物体の固定からの変更点は、rollong_function関数の追加と、nearCallback関数の修正のみです。 まぁ、永遠に転がり続けるのが気に入らなくて作ってみただけなので、精度とかはまったく考えてません。 あくまで参考まで。 全ソースコード #include ode/ode.h #include drawstuff/drawstuff.h #define MAX_CONTACTS 4 static dWorldID world; static dSpaceID space; static dJointGroupID contactgroup; static dBodyID b_sphere; static dGeomID g_sphere; static dGeomID g_fixed; static dReal radius = 0.5; static dReal f_box_sizes[3] = { 2.0, 2.0, 1.0 }; #ifdef dDOUBLE # define dsDrawSphere dsDrawSphereD # define dsDrawBox dsDrawBoxD #endif // // 簡易 転がり摩擦計算関数 // [引数] // o ジオメトリID // coef 転がり摩擦係数 // // [計算方法] // F = f * (W / r) // F 転がり摩擦[N] // f 転がり摩擦係数 // r 物体の半径 // void rolling_function( dGeomID o, dReal coef, dContact *c ) { if (o dGeomGetClass(o) == dSphereClass) { dBodyID b = dGeomGetBody(o); if (!b) return; dMass m; dBodyGetMass( b, m ); dReal* normal = c- geom.normal; // 垂直抗力ベクトル dReal w = m.mass*(normal[2]*9.8); // 質量, (memo 角度差cosΘ = (normal[0]*0.0 + normal[1]*0.0 + normal[2]*1.0)) dReal r = dGeomSphereGetRadius( o ); // 半径 dReal F = coef * (w / r ); // 転がり摩擦(力) dReal T = F * r; // 転がり摩擦のトルク? const dReal* av = dBodyGetAngularVel(b); /* const dReal* lv = dBodyGetLinearVel(b); printf( "sphre w=%.3f, r=%.3f, F=%.3f, T=%.3f", w, r, F, T ); printf( ", av=(%.3f,%.3f,%.3f)", av[0], av[1], av[2] ); printf( ", lv=(%.3f,%.3f,%.3f)", lv[0], lv[1], lv[2] ); printf( "\n" ); */ dReal a_speed = sqrt(av[0]*av[0] + av[1]*av[1] + av[2]*av[2]); // 回転スピード if (a_speed 1.0e-5) { dReal n_av[3] = { av[0]/a_speed, av[1]/a_speed, av[2]/a_speed }; // 回転方向の正規化 dBodyAddTorque( b, -n_av[0]*T, -n_av[1]*T, -n_av[2]*T ); // 転がり摩擦をトルクとしてあたえる } else { dBodySetAngularVel( b, 0.0f, 0.0f, 0.0f ); // 停止 } } } static void nearCallback( void *data, dGeomID o1, dGeomID o2 ) { dBodyID b1 = dGeomGetBody( o1 ); dBodyID b2 = dGeomGetBody( o2 ); if ( b1 b2 dAreConnectedExcluding( b1, b2, dJointTypeContact ) ) return; dContact contact[MAX_CONTACTS]; for ( int i=0; i MAX_CONTACTS; i++ ) { //contact[i].surface.mode = dContactBounce | dContactSoftERP | dContactSoftCFM; contact[i].surface.mode = dContactBounce | dContactApprox1; contact[i].surface.mu = 1.0; // dInfinity; contact[i].surface.bounce = 0.5; //contact[i].surface.soft_erp = 0.2; //contact[i].surface.soft_cfm = 0.00001; } int numc = dCollide( o1, o2, MAX_CONTACTS, contact[0].geom, sizeof( dContact ) ); if ( numc 0 ) { for ( int i=0; i numc; i++ ) { dJointID c = dJointCreateContact( world, contactgroup, contact+i ); dJointAttach( c, b1, b2 ); // 転がり摩擦 rolling_function( o1, 0.02, contact+i ); rolling_function( o2, 0.02, contact+i ); } } } // start simulation - set viewpoint static void start() { static float xyz[3] = { 0.0f, 7.0f, 5.0f }; static float hpr[3] = { -125.f, -15.f, 0.f }; dsSetViewpoint( xyz, hpr ); } // simulation loop static void simLoop( int pause ) { dSpaceCollide( space, 0, nearCallback ); if (!pause) { dWorldStep( world, 0.005 ); } dJointGroupEmpty( contactgroup ); dsSetColor( 1.0, 1.0, 0.0 ); dsDrawSphere( dBodyGetPosition( b_sphere ), dBodyGetRotation( b_sphere ), radius ); dsSetColor( 0.5, 0.5, 0.5 ); dsDrawBox( dGeomGetPosition( g_fixed ), dGeomGetRotation( g_fixed ), f_box_sizes ); /* const dReal* pos = dBodyGetPosition( b_sphere ); printf( "x=%.5f, y=%.5f, z=%.5f\n", pos[0], pos[1], pos[2] ); */ } int main( int argc, char* argv[] ) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = start; fn.step = simLoop; fn.command = 0; fn.stop = 0; fn.path_to_textures = "../../drawstuff/textures"; dInitODE(); // creating world world = dWorldCreate(); space = dHashSpaceCreate( 0 ); contactgroup = dJointGroupCreate( 0 ); dCreatePlane( space, 0, 0, 1, 0 ); dWorldSetGravity( world, 0.0, 0.0, -9.8 ); dWorldSetERP( world, 0.8 ); dWorldSetCFM( world, 0.00001 ); // creating Sphere b_sphere = dBodyCreate( world ); dReal pos[3] = { 0.0, 0.0, 5.0 }; dBodySetPosition( b_sphere, pos[0], pos[1], pos[2] ); dMass sphere_mass; dMassSetSphere( sphere_mass, 1.0, radius ); dBodySetMass( b_sphere, sphere_mass ); g_sphere = dCreateSphere( space, radius ); dGeomSetBody( g_sphere, b_sphere ); // creating Fixed Box g_fixed = dCreateBox( space, f_box_sizes[0], f_box_sizes[1], f_box_sizes[2] ); dMatrix3 R; //dRFromAxisAndAngle( R, 0, 1, 0, -0.30 ); dRFromAxisAndAngle( R, 0, 1, 0.5, -0.30 ); dGeomSetRotation( g_fixed, R); // 方向指定 dGeomSetPosition( g_fixed, 0.0, 0.0, 0.5 ); // 位置指定 // starting simulation dsSimulationLoop( argc, argv, 320, 240, fn ); dJointGroupDestroy( contactgroup ); dSpaceDestroy( space ); dWorldDestroy( world ); return 0; } 以上
https://w.atwiki.jp/bambooflow/pages/223.html
ODEでポリゴンを扱う 3Dフォーマット・ファイルを読み込んで表示するためのクラス、方法を紹介。 ODEでSTLファイルのポリゴンを表示する ODEでXファイルのポリゴンを表示する 3ds形式を読み込む方法について メモ 基礎用語 頂点(vertex) 辺(edge) 面(surface) 法線(normal) 多角面:ポリゴン(polygon) 凸ポリゴン(convex polygon)すべての頂点の内角は180度未満 任意の直線との交点は2つ 頂点順でポリゴンを複数の三角メッシュに分割可 2次曲面:球体や円柱などの表面をポリゴンメッシュにて表現 自由曲面(free-from surface):パッチを複数個つないで3次元面を表現 ベジェ曲面 B-スプライン曲面 ナーブス(NURBS)曲面 CSG(Constructive Solid Geometry) エレベーショングリッド(elevation grid)地形や水面を表現 高さ情報だけ エクストルージョン(extrusion) メタボール(meta-ball)
https://w.atwiki.jp/bambooflow/pages/211.html
glutでODE テスト中 ode_draw01.zip ObjectBase.h ObjectBase.cpp Sphere.h Sphere.cpp Box.h Box.cpp main.cpp ボールを表示。落下。 ボックス表示。落下。 地面に衝突。 実装機能Sphere(球体)の生成、表示 drawstufと類似したカメラ操作(マウス操作) glutによるグラフィック表示 Box(箱)の生成、表示 vectorにより、3D表示の自動化 下記のチュートリアルを参考にしてます。 http //artis.imag.fr/Membres/Xavier.Decoret/resources/ode/tutorial1.html; ObjectBase.h 重要な部分は、render()とrenderInLocalFrame()=0の実装。 3D表示のための簡易的な機構になります。 #include ode/ode.h class ObjectBase { protected dBodyID body; dGeomID geom; public virtual ~ObjectBase(); virtual void render() const; void setPosition(dReal x, dReal y, dReal z); protected virtual void renderInLocalFrame() const = 0; }; void ObjectBase render() const { glPushMatrix(); const dReal *p = dBodyGetPosition(body); const dReal *r = dBodyGetRotation(body); float m[16]; m[ 0] = (GLfloat)r[ 0]; m[ 1] = (GLfloat)r[ 4]; m[ 2] = (GLfloat)r[ 8]; m[ 3] = (GLfloat)0; m[ 4] = (GLfloat)r[ 1]; m[ 5] = (GLfloat)r[ 5]; m[ 6] = (GLfloat)r[ 9]; m[ 7] = (GLfloat)0; m[ 8] = (GLfloat)r[ 2]; m[ 9] = (GLfloat)r[ 6]; m[10] = (GLfloat)r[10]; m[11] = (GLfloat)0; m[12] = (GLfloat)p[ 0]; m[13] = (GLfloat)p[ 1]; m[14] = (GLfloat)p[ 2]; m[15] = (GLfloat)1; glMultMatrixf( m ); renderInLocalFrame(); glPopMatrix(); }
https://w.atwiki.jp/bambooflow/pages/96.html
物体の固定 ここでは物体を固定する方法について説明します。 実は簡単で、固定したいオブジェクトを衝突検出のみさせるようにすればよいだけです。 つまり、dGeomIDは設定する必要はあるがdBodyIDを設定する必要はないということです。 dBodyIDを設定しなければ物体は移動することができず、その場所に固定されます。 static dGeomID g_fixed; g_fixed = dCreateBox( space, f_box_sizes[0], f_box_sizes[1], f_box_sizes[2] ); このとき、dGeomSetBodyは設定しません。 サンプルコード fixed_obj.tgz; - ODE v0.9 fixed_obj_v02.tgz; - ODE v0.11 ODE付属のサンプルコードでdemo_buggy.cppを参考にしました。 /*********************************************************** * Hajime no Ippo --- file hjime.cpp ***********************************************************/ #include ode/ode.h #include drawstuff/drawstuff.h #define MAX_CONTACTS 4 static dWorldID world; static dSpaceID space; static dJointGroupID contactgroup; static dBodyID b_sphere; static dGeomID g_sphere; static dGeomID g_fixed; static dReal radius = 0.5; static dReal f_box_sizes[3] = { 2.0, 2.0, 1.0 }; #ifdef dDOUBLE #define dsDrawSphere dsDrawSphereD #define dsDrawBox dsDrawBoxD #endif static void nearCallback( void *data, dGeomID o1, dGeomID o2 ) { dBodyID b1 = dGeomGetBody( o1 ); dBodyID b2 = dGeomGetBody( o2 ); if ( b1 b2 dAreConnectedExcluding( b1, b2, dJointTypeContact ) ) return; dContact contact[MAX_CONTACTS]; for ( int i=0; i MAX_CONTACTS; i++ ) { //contact[i].surface.mode = dContactBounce | dContactSoftERP | dContactSoftCFM; contact[i].surface.mode = dContactBounce; contact[i].surface.mu = dInfinity; contact[i].surface.bounce = 1.0; //contact[i].surface.soft_erp = 0.2; //contact[i].surface.soft_cfm = 0.00001; } int numc = dCollide( o1, o2, MAX_CONTACTS, contact[0].geom, sizeof( dContact ) ); if ( numc 0 ) { for ( int i=0; i numc; i++ ) { dJointID c = dJointCreateContact( world, contactgroup, contact+i ); dJointAttach( c, b1, b2 ); } } } // start simulation - set viewpoint static void start() { static float xyz[3] = { 0.0f, 7.0f, 5.0f }; static float hpr[3] = { -90.f, -15.f, 0.f }; dsSetViewpoint( xyz, hpr ); } // simulation loop static void simLoop( int pause ) { dSpaceCollide( space, 0, nearCallback ); if (!pause) { dWorldStep( world, 0.005 ); } dJointGroupEmpty( contactgroup ); dsSetColor( 1.0, 1.0, 0.0 ); dsDrawSphere( dBodyGetPosition( b_sphere ), dBodyGetRotation( b_sphere ), radius ); dsSetColor( 0.5, 0.5, 0.5 ); dsDrawBox( dGeomGetPosition( g_fixed ), dGeomGetRotation( g_fixed ), f_box_sizes ); } int main( int argc, char* argv[] ) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = start; fn.step = simLoop; fn.command = 0; fn.stop = 0; fn.path_to_textures = "../../drawstuff/textures"; dInitODE(); // creating world world = dWorldCreate(); space = dHashSpaceCreate( 0 ); contactgroup = dJointGroupCreate( 0 ); dCreatePlane( space, 0, 0, 1, 0 ); dWorldSetGravity( world, 0.0, 0.0, -9.8 ); dWorldSetERP( world, 0.8 ); dWorldSetCFM( world, 0.00001 ); // creating Sphere b_sphere = dBodyCreate( world ); dReal pos[3] = { 0.0, 0.0, 5.0 }; dBodySetPosition( b_sphere, pos[0], pos[1], pos[2] ); dMass sphere_mass; dMassSetSphere( sphere_mass, 1.0, radius ); dBodySetMass( b_sphere, sphere_mass ); g_sphere = dCreateSphere( space, radius ); dGeomSetBody( g_sphere, b_sphere ); // creating Fixed Box g_fixed = dCreateBox( space, f_box_sizes[0], f_box_sizes[1], f_box_sizes[2] ); dMatrix3 R; dRFromAxisAndAngle( R, 0, 1, 0, -0.30 ); dGeomSetRotation( g_fixed, R); // 方向指定 dGeomSetPosition( g_fixed, 0.0, 0.0, 0.5 ); // 位置指定 // starting simulation dsSimulationLoop( argc, argv, 320, 240, fn ); dJointGroupDestroy( contactgroup ); dSpaceDestroy( space ); dWorldDestroy( world ); return 0; } 以上
https://w.atwiki.jp/bambooflow/pages/213.html
glutでODE テスト中 ode_draw02.zip ode_draw03.zip ode_draw04pre.zip ObjectBase.h ObjectBase.cpp Sphere.h Sphere.cpp Box.h Box.cpp main.cpp ボールを表示。落下。 ボックス表示。落下。 地面に衝突。 実装機能Sphere(球体)の生成、表示 drawstufと類似したカメラ操作(マウス操作) glutによるグラフィック表示 Box(箱)の生成、表示 vectorにより、3D表示の自動化 groundをObjectBaseに変更 Cylinderオブジェクト追加 下記のチュートリアルを参考にしてます。 http //artis.imag.fr/Membres/Xavier.Decoret/resources/ode/tutorial1.html ObjectBase.h 重要な部分は、render()とrenderInLocalFrame()=0の実装。 3D表示のための簡易的な機構になります。 #include ode/ode.h class ObjectBase { protected dBodyID body; dGeomID geom; public virtual ~ObjectBase(); virtual void render() const; void setPosition(dReal x, dReal y, dReal z); protected virtual void renderInLocalFrame() const = 0; }; void ObjectBase render() const { glPushMatrix(); const dReal *p = dBodyGetPosition(body); const dReal *r = dBodyGetRotation(body); float m[16]; m[ 0] = (GLfloat)r[ 0]; m[ 1] = (GLfloat)r[ 4]; m[ 2] = (GLfloat)r[ 8]; m[ 3] = (GLfloat)0; m[ 4] = (GLfloat)r[ 1]; m[ 5] = (GLfloat)r[ 5]; m[ 6] = (GLfloat)r[ 9]; m[ 7] = (GLfloat)0; m[ 8] = (GLfloat)r[ 2]; m[ 9] = (GLfloat)r[ 6]; m[10] = (GLfloat)r[10]; m[11] = (GLfloat)0; m[12] = (GLfloat)p[ 0]; m[13] = (GLfloat)p[ 1]; m[14] = (GLfloat)p[ 2]; m[15] = (GLfloat)1; glMultMatrixf( m ); renderInLocalFrame(); glPopMatrix(); }